package com.abcd.godating.utils.json;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.deser.CustomDeserializerFactory;
import org.codehaus.jackson.map.deser.StdDeserializerProvider;
import org.codehaus.jackson.map.ser.CustomSerializerFactory;
import org.codehaus.jackson.map.type.TypeFactory;

@SuppressWarnings("deprecation")
public class JsonMarshaller {
    private static Log log = LogFactory.getLog(JsonMarshaller.class);
    private static final ObjectMapper objectMapper = new ObjectMapper();
    
    static{
        objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
            
        CustomDeserializerFactory cdsf = new CustomDeserializerFactory();
        objectMapper.setDeserializerProvider(new StdDeserializerProvider(cdsf));
        cdsf.addSpecificMapping(Date.class, new CustomDateDeserializer());
        cdsf.addSpecificMapping(java.sql.Date.class, new CustomSqlDateDeserializer());
        
        CustomSerializerFactory csf = new CustomSerializerFactory();
        objectMapper.setSerializerFactory(csf);
        csf.addSpecificMapping(Date.class, new CustomDateSerializer());
        csf.addSpecificMapping(java.sql.Date.class, new CustomSqlDateSerializer());
        
        objectMapper.getDeserializationConfig().addHandler(new CustomDeserializationProblemHandler());
    }
    
    /**
     * object to json
     * 
     * @param obj
     * @return
     */
    public static String marshall(Object obj) {
        StringWriter sw = new StringWriter();
        try {
            objectMapper.writeValue(sw, obj);
        } catch (Exception e) {
            log.error("Marshall object to json failed. Object: " + obj);
            
            throw new MarshallException("Marshall object to json failed.", e);
        }
        return sw.toString().replaceAll("\\\\\\\\", "\\\\");
    }

    /**
     * convert json to object (properties is not case sensitive)
     * 
     * @param content       json
     * @param mainClass     object type
     * @param genericClass  
     * @return
     */
    @SuppressWarnings("unchecked")
	public static <I> I  unmarshall(String content, Class<I> mainClass, Class<?>...genericClass) {
        try {
            if(genericClass == null || genericClass.length == 0 || genericClass[0] == null){
                return (I)objectMapper.readValue(new StringReader(content), mainClass);
            }else{
                return (I)objectMapper.readValue(new StringReader(content), TypeFactory
                        .parametricType(mainClass, genericClass));
            }
        } catch (Exception e) {
            log.error("Unmarshall json to object failed. Content: " + content);

            throw new MarshallException("Unmarshall json to object failed.", e);
        }
    }
    
    public static void main(String[] args) {
		Collection<String> userIds = new ArrayList<String>();
		userIds.add("123");
		userIds.add("345");
		String json = JsonMarshaller.marshall(userIds);
		System.out.println(json);
		
		ArrayList<String> result = JsonMarshaller.unmarshall(json, ArrayList.class, String.class);
		System.out.println(result);
	}
}